/**
 * @file    drv_spi.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, spi抽象层
 * @version 1.03
 * @date    2025-07-08
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-08     yhy          the first version V1.00
 * 2025-07-11     yhy          所有函数和变量名修改为snf_开头 V1.01
 * 2025-07-18     yhy          完善spi统一回调函数, 实现了spi-dma循环发送 V1.02
 * 2025-07-24     yhy          IMMO修改了spi-dma发送的库函数，实现啦真正的SPI-DMA循环发送 V1.03
 *
 */
#include "drv_spi.h"

#include "dma_drv.h"
#include "drv_gpio.h"
#include "gpio_drv.h"
#include "spi_drv.h"
#include "spi_reg_access.h"

#define SPI_DMA_TRANSFER_MIN_DATA_SIZE 6 /* 当数据量小于6个字节时, 不使用DMA */

/**
 * @brief SPI引脚路由
 *
 */
typedef struct
{
    GPIO_Type     *mosi_port; /*!< SPI MOSI引脚端口 */
    uint32_t       mosi_pin;  /*!< SPI MOSI引脚编号 */
    GPIO_Type     *sck_port;  /*!< SPI SCK引脚端口 */
    uint32_t       sck_pin;   /*!< SPI SCK引脚编号 */
    GPIO_Type     *cs_port;   /*!< SPI CS引脚端口 */
    uint32_t       cs_pin;    /*!< SPI CS引脚编号 */
    GPIO_Type     *miso_port; /*!< SPI MISO引脚端口 */
    uint32_t       miso_pin;  /*!< SPI MISO引脚编号  */
    gpio_pin_mux_t mux;       /*!< SPI 引脚复用 */
} snf_spi_pin_route_t;

/**
 * @brief SPI硬件实例管理
 *
 */
typedef struct
{
    bool               initialized;    /*!< SPI实例是否初始化 */
    snf_spi_instance_e instance;       /*!< SPI软件实例编号 */
    spi_callback_f     callback;       /*!< SPI回调函数, 当SPI传输完成时调用 */
    void              *callback_param; /*!< SPI回调函数参数 */
    spi_state_t        state;          /*!< SPI状态 */
    SPI_Type          *spiX_addr;      /*!< SPI实例地址 */
} snf_spi_hw_manager_t;

static result_e  snf_drv_spi_validate_instance(snf_spi_instance_e instance);
static uint32_t  snf_drv_spi_get_hw_instance(snf_spi_instance_e instance);
static SPI_Type *snf_drv_spi_get_hw_instance_addr(uint32_t hw_instance);
static void      snf_drv_spi_gpio_init(const snf_spi_config_t *spi_config);
static result_e  snf_drv_spi_convert_errcode(errcode_t errcode);
static void      snf_drv_spi_callback(uint32_t hw_instance, spi_event_t event, void *param);
static result_e  snf_drv_spi_validate_trans_param(snf_spi_instance_e instance, uint8_t *tx_buf,
                                                  uint8_t *rx_buf, uint32_t buf_size);
static uint32_t  snf_drv_spi_get_data_size(snf_spi_data_size_e data_size);

static spi_master_config_t spi_base_config = {
    .isContinuousMode = false,                    	/*!< 转移是否是持续性的 */
    .pinConfig        = SPI_PIN_SOUT_MISO_SIN_MOSI, /*!< 数据线极性 */
	.baudConfig       = {							/*!<波特率配置， 15MHz */
		.sckHigh = 0U,
		.sckLow  = 0U,
	},
	.csTiming = {									/*!< 片选时间 */
		.csSetup = 5U,
		.csHold  = 5U,
		.csIdle  = 5U,
	},
	.csPin = SPI_CS0,
	.csPol = SPI_CS_POL_LOW,						/*!< 片选极性, 低有效 */
	.clkPol = SPI_CLK_POL_LOW,						/*!< 时钟极性, 空闲状态下为低电平 */
	.clkPha = SPI_CLK_PHA_1ST,						/*!< 时钟相位, 第一个边沿采样 */
	.frameSize = SPI_FRAME_SIZE_32BIT,				/*!< 数据宽度: 32bit */
	.txOrder = SPI_TRANSFER_ORDER_MSB,				/*!< 传输顺序: 高位在前 */
	.rxOrder = SPI_TRANSFER_ORDER_MSB,				/*!< 接收顺序: 高位在前 */
	.sampleDelay = SPI_SAMPLE_DELAY_NONE,			/*!< 采样延迟: 无 */
	.transferType = SPI_USING_DMA,					/*!< 传输类型: DMA */
	.txDMAChannel = 0U,
	.rxDMAChannel = 1U,
	.callback = NULL,
	.callbackParam = NULL,
};

/* SPI引脚配置表 */
static const snf_spi_pin_route_t spi_pin_route_table[SPI_INSTANCE_MAXSIZE] = {
    [SPI_INSTANCE_SPI0_0] = { GPIOD, 16U, GPIOD, 15U, GPIOB, 5U, GPIOB, 4U, GPIO_PIN_MUX_FUN4 },
    [SPI_INSTANCE_SPI0_1] = { GPIOB, 3U, GPIOB, 2U, GPIOB, 0U, GPIOB, 1U, GPIO_PIN_MUX_FUN3 },
    [SPI_INSTANCE_SPI0_2] = { GPIOA, 1U, GPIOA, 0U, GPIOE, 6U, GPIOE, 2U, GPIO_PIN_MUX_FUN4 },
    [SPI_INSTANCE_SPI0_3] = { GPIOE, 1U, GPIOE, 0U, GPIOA, 10U, GPIOA, 11U, GPIO_PIN_MUX_FUN4 },
    [SPI_INSTANCE_SPI1_0] = { GPIOD, 1U, GPIOD, 0U, GPIOD, 3U, GPIOD, 2U, GPIO_PIN_MUX_FUN3 },
    [SPI_INSTANCE_SPI1_1] = { GPIOC, 7U, GPIOC, 6U, GPIOA, 12U, GPIOA, 13U, GPIO_PIN_MUX_FUN3 },
    [SPI_INSTANCE_SPI2_0] = { GPIOC, 0U, GPIOC, 15U, GPIOC, 14U, GPIOC, 1U, GPIO_PIN_MUX_FUN4 },
};

/* SPI硬件实例管理 */
static snf_spi_hw_manager_t spi_hw_manager_list[SPI_HW_INSTANCE_MAXSIZE] = { 0 };

/**
 * @brief 初始化SPI
 *
 * @param spi_config    spi配置结构体指针
 * @return result_e     初始化结果, RESULT_STATUS_OK标识初始化成功, 其他值表示初始化失败
 */
result_e snf_drv_spi_init(const snf_spi_config_t *spi_config)
{
    if (spi_config == NULL || spi_config->data_size >= SPI_DATA_SIZE_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 校验spi实例 */
    result_e result = snf_drv_spi_validate_instance(spi_config->instance);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    /* 获取硬件实例编号 */
    uint32_t hw_instance = snf_drv_spi_get_hw_instance(spi_config->instance);
    if (hw_instance >= SPI_HW_INSTANCE_MAXSIZE) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    spi_hw_manager_list[hw_instance].spiX_addr      = snf_drv_spi_get_hw_instance_addr(hw_instance);
    spi_hw_manager_list[hw_instance].callback       = spi_config->spi_callback;
    spi_hw_manager_list[hw_instance].callback_param = spi_config->callback_param;
    spi_hw_manager_list[hw_instance].instance       = spi_config->instance;

    /* GPIO初始化 */
    snf_drv_spi_gpio_init(spi_config);

    spi_base_config.frameSize = (spi_frame_size_t)snf_drv_spi_get_data_size(spi_config->data_size);

    /* 初始化SPI */
    errcode_t ret =
        SPI_MasterInit(hw_instance, &(spi_hw_manager_list[hw_instance].state), &spi_base_config);
    if (ret != ERR_SUCCESS) {
        return snf_drv_spi_convert_errcode(ret);
    }

    /* 注册回调函数 */
    SPI_InstallCallback(hw_instance, snf_drv_spi_callback, NULL);

    spi_hw_manager_list[hw_instance].initialized = true;

    return RESULT_STATUS_OK;
}

/**
 * @brief  SPI数据传输
 *
 * @param instance      SPI实例
 * @param tx_buf        发送缓冲区
 * @param rx_buf        接收缓冲区
 * @param buf_size      缓冲区大小
 * @return result_e     传输结果, RESULT_STATUS_OK表示传输成功, 其他值表示传输失败
 */
result_e snf_drv_spi_transfer(snf_spi_instance_e instance, uint8_t *tx_buf, uint8_t *rx_buf,
                              uint32_t buf_size)
{
    /* 检查发送参数 */
    result_e result = snf_drv_spi_validate_trans_param(instance, tx_buf, rx_buf, buf_size);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    uint32_t hw_instance = snf_drv_spi_get_hw_instance(instance);

    /* 根据buf_size来决定使用DMA还是非DMA */
    errcode_t ret;
    if (buf_size < SPI_DMA_TRANSFER_MIN_DATA_SIZE) {
        ret = SPI_MasterTransferPolling(hw_instance, tx_buf, rx_buf, buf_size);
    }
    else {
        ret = SPI_MasterTransfer(hw_instance, tx_buf, rx_buf, buf_size);
    }

    if (ret != ERR_SUCCESS) {
        return snf_drv_spi_convert_errcode(ret);
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief 获取数据宽度
 *
 * @param data_size     用户数据宽度
 * @return uint32_t     库函数 数据宽度数值
 */
static uint32_t snf_drv_spi_get_data_size(snf_spi_data_size_e data_size)
{
    static uint32_t data_size_table[SPI_DATA_SIZE_MAX] = {
        [SPI_DATA_SIZE_8BIT]  = SPI_FRAME_SIZE_8BIT,
        [SPI_DATA_SIZE_16BIT] = SPI_FRAME_SIZE_16BIT,
        [SPI_DATA_SIZE_32BIT] = SPI_FRAME_SIZE_32BIT,
    };

    return data_size_table[data_size];
}

/**
 * @brief 检查发送函数参数
 *
 * @param instance      SPI实例
 * @param tx_buf        发送缓冲区
 * @param rx_buf        接收缓冲区
 * @param buf_size      缓冲区大小
 * @return result_e     状态码
 */
static result_e snf_drv_spi_validate_trans_param(snf_spi_instance_e instance, uint8_t *tx_buf,
                                                 uint8_t *rx_buf, uint32_t buf_size)
{
    /* 校验spi实例 */
    result_e result = snf_drv_spi_validate_instance(instance);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    if (tx_buf == NULL && rx_buf == NULL) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (buf_size == 0) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief  errcode转换成SPI状态码
 *
 * @param errcode       错误码
 * @return result_e     SPI状态码
 */
static result_e snf_drv_spi_convert_errcode(errcode_t errcode)
{
    switch (errcode) {
    case ERR_SPI_TX_UNDERRUN: return RESULT_STATUS_SPI_TX_UNDERRUN;
    case ERR_SPI_RX_OVERFLOW: return RESULT_STATUS_SPI_RX_OVERRUN;
    case ERR_SPI_ABORTED:     return RESULT_STATUS_SPI_ABORTED;
    default:                  return RESULT_STATUS_SPI_ERROR;
    }
}

/**
 * @brief 初始化SPI的GPIO
 *
 * @param spi_config SPI配置
 */
static void snf_drv_spi_gpio_init(const snf_spi_config_t *spi_config)
{
    /* 配置SPI引脚 */
    const snf_spi_pin_route_t *spi_pin_config = &spi_pin_route_table[spi_config->instance];

    GPIO_SetPinFunc(spi_pin_config->mosi_port, spi_pin_config->mosi_pin, spi_pin_config->mux);
    GPIO_SetPinFunc(spi_pin_config->sck_port, spi_pin_config->sck_pin, spi_pin_config->mux);
    GPIO_SetPinFunc(spi_pin_config->cs_port, spi_pin_config->cs_pin, spi_pin_config->mux);
    GPIO_SetPinFunc(spi_pin_config->miso_port, spi_pin_config->miso_pin, spi_pin_config->mux);
}

/**
 * @brief 获取SPI硬件实例地址
 *
 * @param hw_instance 	硬件实例编号
 * @return SPI_Type* 	硬件实例地址
 */
static SPI_Type *snf_drv_spi_get_hw_instance_addr(uint32_t hw_instance)
{
    /* 在调用该函数前, 已经验证了参数, 所以这里不需要再次检查参数 */

    static SPI_Type *spi_hw_instance_table[] = { SPI0, SPI1, SPI2 };

    return spi_hw_instance_table[hw_instance];
}

/**
 * @brief 获取SPI硬件实例编号
 *
 * @param instance 		SPI实例
 * @return uint32_t 	硬件实例编号
 */
static uint32_t snf_drv_spi_get_hw_instance(snf_spi_instance_e instance)
{
    static uint32_t instance_table[SPI_INSTANCE_MAXSIZE] = {
        [SPI_INSTANCE_SPI0_0] = 0U, [SPI_INSTANCE_SPI0_1] = 0U, [SPI_INSTANCE_SPI0_2] = 0U,
        [SPI_INSTANCE_SPI0_3] = 0U, [SPI_INSTANCE_SPI1_0] = 1U, [SPI_INSTANCE_SPI1_1] = 1U,
        [SPI_INSTANCE_SPI2_0] = 2U,
    };

    return instance_table[(uint32_t)instance];
}

/**
 * @brief 校验SPI实例是否有效
 *
 * @param instance 		SPI实例
 * @return result_e 	校验结果
 */
static result_e snf_drv_spi_validate_instance(snf_spi_instance_e instance)
{
    if (instance < SPI_INSTANCE_MAX) {
        return RESULT_STATUS_OK;
    }

    return RESULT_STATUS_INVALID_PARAM;
}

/**
 * @brief  SPI回调函数
 *
 * @param hw_instance
 * @param event
 * @param param
 */
static void snf_drv_spi_callback(uint32_t hw_instance, spi_event_t event, void *param)
{
    //    snf_spi_hw_manager_t spi_hw_manager = spi_hw_manager_list[hw_instance];

    //    if (!spi_hw_manager.initialized) {
    //        return;
    //    }

    //    switch (event) {
    //    case SPI_EVENT_END_TRANSFER:
    //        snf_drv_spi_transfer(spi_hw_manager.instance, spi_data_packet[hw_instance].tx_buf,
    //                             spi_data_packet[hw_instance].rx_buf,
    //                             spi_data_packet[hw_instance].buf_size);
    //        break;
    //    }
}
